package com.zhiwen.service.impl;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.zhiwen.service.SensitiveContentService;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;


import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 敏感内容检测服务实现类
 */
@Service
@Slf4j
public class SensitiveContentServiceImpl implements SensitiveContentService {

    private static final String SENSITIVE_WORDS_KEY = "system:sensitive:words";
    private static final String AUTO_REVIEW_CONFIG_KEY = "system:auto_review:config";
    private static final String SENSITIVE_WORDS_TRIE_KEY = "system:sensitive:words:trie";

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    // 默认敏感词列表
    private static final List<String> DEFAULT_SENSITIVE_WORDS = Arrays.asList(
            "暴力", "色情", "赌博", "政治", "诈骗", "违法", "黄赌毒", "侮辱", "仇恨", "恐怖",
            "非法", "歧视", "军火", "黑客", "病毒", "钓鱼", "欺诈", "毒品", "传销", "自杀"
    );

    // 默认自动审核配置
    private static final Map<String, Object> DEFAULT_AUTO_REVIEW_CONFIG = new HashMap<>() {{
        put("enabled", true);
        put("sensitivityLevel", "medium"); // low, medium, high
        put("autoRejectEnabled", false);
        put("maxSensitiveWordsAllowed", 3);
        put("cacheDuration", 3600); // 缓存时间，单位秒
    }};

    // AC自动机的字典树节点
    private static class TrieNode {
        Map<Character, TrieNode> children = new HashMap<>();
        boolean isEndOfWord;
        String word;
        TrieNode fail;

        TrieNode() {
            this.isEndOfWord = false;
            this.word = null;
            this.fail = null;
        }
    }

    private TrieNode root;

    @PostConstruct
    public void init() {
        // 初始化敏感词列表
        if (getSensitiveWords().isEmpty()) {
            setSensitiveWords(DEFAULT_SENSITIVE_WORDS);
        }

        // 初始化自动审核配置
        if (getAutoReviewConfig().isEmpty()) {
            setAutoReviewConfig(DEFAULT_AUTO_REVIEW_CONFIG);
        }

        // 初始化AC自动机
        buildAcAutomaton();
    }

    /**
     * 构建AC自动机
     */
    private void buildAcAutomaton() {
        // 获取敏感词列表
        List<String> sensitiveWords = getSensitiveWords();

        // 创建字典树
        root = new TrieNode();

        // 构建Trie树
        for (String word : sensitiveWords) {
            insert(word);
        }

        // 构建失败指针
        buildFailurePointers();

        // 将AC自动机缓存到Redis
        cacheTrieToRedis();
    }

    /**
     * 向字典树中插入单词
     */
    private void insert(String word) {
        if (StringUtils.isBlank(word)) {
            return;
        }

        TrieNode node = root;
        for (char c : word.toCharArray()) {
            node.children.putIfAbsent(c, new TrieNode());
            node = node.children.get(c);
        }
        node.isEndOfWord = true;
        node.word = word;
    }

    /**
     * 构建失败指针
     */
    private void buildFailurePointers() {
        Queue<TrieNode> queue = new LinkedList<>();

        // 根节点的子节点的失败指针指向根
        for (Map.Entry<Character, TrieNode> entry : root.children.entrySet()) {
            TrieNode child = entry.getValue();
            child.fail = root;
            queue.offer(child);
        }

        // BFS构建其他节点的失败指针
        while (!queue.isEmpty()) {
            TrieNode current = queue.poll();

            for (Map.Entry<Character, TrieNode> entry : current.children.entrySet()) {
                char c = entry.getKey();
                TrieNode child = entry.getValue();

                // 将孩子节点入队
                queue.offer(child);

                // 获取当前节点的失败指针
                TrieNode failNode = current.fail;

                // 寻找合适的失败指针
                while (failNode != null && !failNode.children.containsKey(c)) {
                    failNode = failNode.fail;
                }

                if (failNode == null) {
                    child.fail = root;
                } else {
                    child.fail = failNode.children.get(c);
                }
            }
        }
    }

    /**
     * 将AC自动机缓存到Redis
     */
    private void cacheTrieToRedis() {
        // 该方法实现复杂，实际项目中可能不直接缓存整个AC自动机结构
        // 这里仅做标记，实际应用中应当考虑序列化与反序列化的复杂性
        Map<String, Object> config = getAutoReviewConfig();
        int cacheDuration = config.containsKey("cacheDuration") ?
            Integer.parseInt(config.get("cacheDuration").toString()) : 3600;
        redisTemplate.opsForValue().set(SENSITIVE_WORDS_TRIE_KEY, "cached", cacheDuration, TimeUnit.SECONDS);
    }

    @Override
    @CacheEvict(value = {"sensitiveWords", "sensitiveContentDetection"}, allEntries = true)
    public boolean setSensitiveWords(List<String> sensitiveWords) {
        try {
            redisTemplate.delete(SENSITIVE_WORDS_KEY);
            if (sensitiveWords != null && !sensitiveWords.isEmpty()) {
                // 将List<String>转换为Object[]
                Object[] words = sensitiveWords.toArray();
                redisTemplate.opsForList().rightPushAll(SENSITIVE_WORDS_KEY, words);
            }

            // 重建AC自动机
            buildAcAutomaton();

            return true;
        } catch (Exception e) {
            log.error("设置敏感词失败: {}", e.getMessage());
            return false;
        }
    }

    @Override
    @Cacheable(value = "sensitiveWords", unless = "#result == null || #result.isEmpty()")
    public List<String> getSensitiveWords() {
        try {
            Long size = redisTemplate.opsForList().size(SENSITIVE_WORDS_KEY);
            if (size == null || size == 0) {
                return new ArrayList<>();
            }

            List<Object> objects = redisTemplate.opsForList().range(SENSITIVE_WORDS_KEY, 0, size - 1);
            return objects.stream()
                    .map(Object::toString)
                    .collect(Collectors.toList());
        } catch (Exception e) {
            log.error("获取敏感词失败: {}", e.getMessage());
            return new ArrayList<>();
        }
    }

    @Override
    @Cacheable(value = "sensitiveContentDetection", key = "#text", unless = "#text == null || #text.length() < 5")
    public Map<String, Object> detectSensitiveContent(String text) {
        Map<String, Object> result = new HashMap<>();
        Set<String> detectedWords = new HashSet<>();
        boolean passed = true;

        if (StringUtils.isBlank(text)) {
            result.put("passed", true);
            result.put("sensitiveWords", new ArrayList<>());
            return result;
        }

        // 使用AC自动机进行高效匹配
        detectedWords = searchWithAcAutomaton(text);

        // 获取配置
        Map<String, Object> config = getAutoReviewConfig();
        int maxAllowed = config.containsKey("maxSensitiveWordsAllowed") ?
            Integer.parseInt(config.get("maxSensitiveWordsAllowed").toString()) : 3;

        // 根据检测到的敏感词数量决定是否通过
        if (!detectedWords.isEmpty() && detectedWords.size() > maxAllowed) {
            passed = false;
        }

        result.put("passed", passed);
        result.put("sensitiveWords", new ArrayList<>(detectedWords));

        return result;
    }

    /**
     * 使用AC自动机搜索敏感词
     */
    private Set<String> searchWithAcAutomaton(String text) {
        Set<String> result = new HashSet<>();

        if (root == null) {
            buildAcAutomaton();
        }

        TrieNode current = root;

        // 遍历文本
        for (int i = 0; i < text.length(); i++) {
            char c = text.charAt(i);

            // 如果当前节点没有对应的子节点，则跟随失败指针继续查找
            while (current != root && !current.children.containsKey(c)) {
                current = current.fail;
            }

            // 找到对应的子节点
            if (current.children.containsKey(c)) {
                current = current.children.get(c);
            }

            // 检查是否匹配到敏感词
            TrieNode temp = current;
            while (temp != root) {
                if (temp.isEndOfWord && temp.word != null) {
                    result.add(temp.word);
                }
                temp = temp.fail;
            }
        }

        return result;
    }

    @Override
    @CacheEvict(value = "autoReviewConfig", allEntries = true)
    public boolean setAutoReviewConfig(Map<String, Object> config) {
        try {
            redisTemplate.opsForHash().putAll(AUTO_REVIEW_CONFIG_KEY, config);

            // 更新缓存过期时间
            if (config.containsKey("cacheDuration")) {
                int cacheDuration = Integer.parseInt(config.get("cacheDuration").toString());
                redisTemplate.expire(SENSITIVE_WORDS_TRIE_KEY, cacheDuration, TimeUnit.SECONDS);
            }

            return true;
        } catch (Exception e) {
            log.error("设置自动审核配置失败: {}", e.getMessage());
            return false;
        }
    }

    @Override
    @Cacheable(value = "autoReviewConfig", unless = "#result == null || #result.isEmpty()")
    public Map<String, Object> getAutoReviewConfig() {
        try {
            Map<Object, Object> entries = redisTemplate.opsForHash().entries(AUTO_REVIEW_CONFIG_KEY);
            if (entries == null || entries.isEmpty()) {
                return new HashMap<>();
            }

            // 转换Map<Object, Object>为Map<String, Object>
            Map<String, Object> config = new HashMap<>();
            for (Map.Entry<Object, Object> entry : entries.entrySet()) {
                config.put(entry.getKey().toString(), entry.getValue());
            }

            return config;
        } catch (Exception e) {
            log.error("获取自动审核配置失败: {}", e.getMessage());
            return new HashMap<>();
        }
    }

    @Override
    @Cacheable(value = "autoReviewResult", key = "#content", unless = "#content == null || #content.length() < 10")
    public String autoReviewContent(String content) {
        if (StringUtils.isBlank(content)) {
            return "通过";
        }

        // 获取配置信息
        Map<String, Object> config = getAutoReviewConfig();
        boolean enabled = Boolean.parseBoolean(config.getOrDefault("enabled", true).toString());
        boolean autoRejectEnabled = Boolean.parseBoolean(config.getOrDefault("autoRejectEnabled", false).toString());
        String sensitivityLevel = config.getOrDefault("sensitivityLevel", "medium").toString();

        // 如果未启用自动审核，则需要人工审核
        if (!enabled) {
            return "人工审核";
        }

        // 检测内容是否包含敏感词
        Map<String, Object> detectResult = detectSensitiveContent(content);
        boolean passed = (boolean) detectResult.get("passed");
        List<String> sensitiveWords = (List<String>) detectResult.get("sensitiveWords");

        // 如果没有敏感词，则通过
        if (sensitiveWords.isEmpty()) {
            return "通过";
        }

        // 根据敏感词数量和敏感级别决定审核结果
        int sensitiveWordCount = sensitiveWords.size();

        // 根据敏感级别设置阈值
        int rejectThreshold;
        switch (sensitivityLevel) {
            case "low":
                rejectThreshold = 5;
                break;
            case "high":
                rejectThreshold = 1;
                break;
            default: // medium
                rejectThreshold = 3;
                break;
        }

        // 如果敏感词数量超过阈值，且启用了自动拒绝，则拒绝
        if (sensitiveWordCount >= rejectThreshold && autoRejectEnabled) {
            return "拒绝";
        }

        // 否则需要人工审核
        return "人工审核";
    }
}
